﻿// ********************************************
// ClassName  ：  {filename}
// Author        ：  
// Company     ： 智测心控
// Version        ：V1.0
// CreateTime ： {date}
// Description ：  
// ********************************************

using System;
using System.IO;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading;
using System.Xml.Serialization;

namespace Common.Common
{
    /// <summary>
    /// 通用帮助类
    /// </summary>
    public static class CommonHelper
    {
        /// <summary>
        /// 获取本机MAC地址
        /// </summary>
        /// <returns>本机MAC地址</returns>
        public static string GetLocalMac()
        {
            string localMac = string.Empty;

            try
            {
                // 获取网卡硬件地址
                var mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
                var moc = mc.GetInstances();

                foreach (ManagementObject mo in moc.OfType<ManagementObject>())
                {
                    if ((bool)mo["IPEnabled"])
                    {
                        localMac = mo["MacAddress"].ToString();

                        // 释放资源
                        mo.Dispose();
                        break;
                    }
                }

                moc.Dispose();
                mc.Dispose();

                return localMac;
            }
            catch
            {
                return localMac;
            }
        }

        /// <summary>
        /// byte数组转16进制字符串
        /// </summary>
        /// <param name="byteDatas">byte数组</param>
        /// <returns>16进制字符串</returns>
        public static string ToHexStrFromBytes(byte[] byteDatas)
        {
            var builder = new StringBuilder();

            foreach (var data in byteDatas)
            {
                builder.Append($"{data:X2} ");
            }

            return builder.ToString().Trim();
        }

        /// <summary>
        /// 线程睡眠
        /// </summary>
        /// <param name="millisecondsTimeout">睡眠毫秒数</param>
        public static void ThreadSleep(int millisecondsTimeout)
        {
            SpinWait.SpinUntil(() => false, millisecondsTimeout);
        }

        /// <summary>
        /// 利用xml序列化和反序列化实现数据深拷贝
        /// </summary>
        /// <typeparam name="T">待深拷贝的数据类型</typeparam>
        /// <param name="obj">待深拷贝的数据</param>
        /// <returns>深拷贝结果</returns>
        public static T DeepCopyByXml<T>(T obj)
        {
            object result;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlSerializer xml = new XmlSerializer(typeof(T));
                xml.Serialize(ms, obj);
                ms.Seek(0, SeekOrigin.Begin);
                result = xml.Deserialize(ms);
                ms.Close();
            }

            return (T)result;
        }

        /// <summary>
        /// 利用反射实现深拷贝
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T DeepCopyWithReflection<T>(T obj)
        {
            Type type = obj.GetType();
            // 如果是字符串或值类型则直接返回
            if (obj is string || type.IsValueType) return obj;
            // 如果是数组
            if (type.IsArray)
            {
                Type elementType = Type.GetType(type.FullName.Replace("[]", string.Empty));
                var array = obj as Array;
                Array copied = Array.CreateInstance(elementType, array.Length);
                for (int i = 0; i < array.Length; i++)
                {
                    copied.SetValue(DeepCopyWithReflection(array.GetValue(i)), i);
                }
                return (T)Convert.ChangeType(copied, obj.GetType());
            }
            object retval = Activator.CreateInstance(obj.GetType());
            System.Reflection.PropertyInfo[] properties = obj.GetType().GetProperties(
                System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic
                | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static);
            foreach (var property in properties)
            {
                var propertyValue = property.GetValue(obj, null);
                if (propertyValue == null)
                    continue;
                property.SetValue(retval, DeepCopyWithReflection(propertyValue), null);
            }
            return (T)retval;
        }

        /// <summary>
        /// 将源数组的数据拷贝到目标数组
        /// </summary>
        /// <param name="sourceArray">源数组</param>
        /// <param name="destinationArray">目标数组</param>
        /// <param name="sourceIndex">原数组起始索引</param> 
        public static void ConstrainedCopy(Array sourceArray, Array destinationArray, int sourceIndex = 0)
        {
            Array.ConstrainedCopy(sourceArray, sourceIndex, destinationArray, 0, destinationArray.Length);
        }

        /// <summary>
        /// 解析串口数据序号
        /// </summary>
        /// <param name="dataArray">串口数据</param>
        /// <returns>序号</returns>
        public static ushort GetSerialNum(byte[] dataArray)
        {
            if (dataArray == null || dataArray.Length < 2)
            {
                return ushort.MinValue;
            }

            var serialNumArray = new byte[2];

            ConstrainedCopy(dataArray, serialNumArray, dataArray.Length - 2);

            return BitConverter.ToUInt16(BitConverter.IsLittleEndian ? serialNumArray.Reverse().ToArray() : serialNumArray, 0);
        }

        public static long GetTimeStamp(DateTime dt)
        {
            DateTime dateStart = new DateTime(1970, 1, 1, 8, 0, 0);
            long timeStamp = Convert.ToInt64((dt - dateStart).TotalMilliseconds);
            return timeStamp;
        }

        public static DateTime UnixTimeToDateTime(int time)
        {
            if (time < 0)
                throw new ArgumentOutOfRangeException("time is out of range");

            return TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)).AddMilliseconds(time);
        }
    }
}
